package com.naspan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.naspan.common.Enum.*;
import com.naspan.common.Result;
import com.naspan.common.config.AppConfig;
import com.naspan.common.constants.Constants;
import com.naspan.common.exception.bizExceptionHandle;
import com.naspan.entity.dto.DownFileDto;
import com.naspan.entity.dto.LoadDataDto;
import com.naspan.entity.dto.UploadFileDto;
import com.naspan.entity.dto.UserSpaceDto;
import com.naspan.entity.po.BaseEntity;
import com.naspan.entity.po.FileInfo;
import com.naspan.entity.vo.LoginUserVo;
import com.naspan.entity.vo.PageDataVo;
import com.naspan.entity.vo.UploadResultVo;
import com.naspan.mapper.UserMapper;
import com.naspan.service.FileInfoService;
import com.naspan.mapper.FileInfoMapper;
import com.naspan.utils.*;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.sql.Array;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【file_info(文件信息)】的数据库操作Service实现
 * @createDate 2023-10-10 11:01:55
 */
@Service
public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements FileInfoService {
    public static final Logger logger = LoggerFactory.getLogger(FileInfoServiceImpl.class);
    public RedisCache redisCache = RedisCacheUtils.getRedisConfig();
    @Resource
    private FileInfoMapper fileInfoMapper;
    @Resource
    private AppConfig appConfig;

    @Resource
    private UserMapper userMapper;

    @Override
    public PageDataVo loadDataList(LoadDataDto fileInfo) {
        FileCategoryEnum categoryEnum = FileCategoryEnum.getByCode(fileInfo.getCategory());
        LoginUserVo loginUser = ServletUtils.getUser();
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        Page<FileInfo> page = new Page<>(fileInfo.getPageNo(), fileInfo.getPageSize());
        if (categoryEnum != null) {
            wrapper.eq(FileInfo::getFileCategory, categoryEnum.getCategory());
        }
        wrapper.eq(FileInfo::getUserId, loginUser.getUserId());
        wrapper.orderByDesc(FileInfo::getLastUpdateTime);
        Page<FileInfo> infoPage = this.page(page, wrapper);
        PageDataVo pageDataVo = PageUtils.getPageList(infoPage);
        return pageDataVo;
    }

    @Override
    public Result newFoloder(String fileName, String filePid) {
        String userId = ServletUtils.getUserId();
        Integer folderType = FileFolderTypeEnum.FOLDER.getType();
        checkFileName(fileName, filePid, folderType);
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileId(String.valueOf(SnowflakeIdUtils.nextId()));
        fileInfo.setFileName(fileName);
        fileInfo.setUserId(userId);
        fileInfo.setFolderType(folderType);
        fileInfo.setFilePid(filePid);
        fileInfo.setStatus(FileStatusEnum.USING.getStatus());
        fileInfo.setDelFlag(FileDelFlagEnum.USING.getFlag());
        super.save(fileInfo);
        return Result.success(fileInfo);
    }

    @Override
    public Result getFolderInfo(String path) {
        String[] fileIds = path.split("/");
        String userId = ServletUtils.getUserId();
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(FileInfo::getFileId, fileIds);
        wrapper.eq(FileInfo::getUserId, userId);
        wrapper.eq(FileInfo::getFolderType, FileFolderTypeEnum.FOLDER.getType());
        String orderBy = "order by field(file_id,\"" + StringUtils.join(fileIds, "\",\"") + "\")";
        wrapper.last(orderBy);
        List<FileInfo> fileInfoList = this.list(wrapper);
        return Result.success(fileInfoList);
    }

    @Override
    public Result rename(String fileName, String fileId) {
        FileInfo fileInfo = this.getById(fileId);
        if (fileInfo == null) {
            throw new bizExceptionHandle("文件不存在");
        }
        String filePid = fileInfo.getFilePid();
        checkFileName(fileName, filePid, fileInfo.getFolderType());
        //如果是文件 后缀需要拼接进去
        if (FileFolderTypeEnum.FILE.getType().equals(fileInfo.getFolderType())) {
            String extension = "." + FilenameUtils.getExtension(fileInfo.getFileName());
            fileName = fileName + extension;
        }
        fileInfo.setFileName(fileName);
        super.saveOrUpdate(fileInfo);
        return Result.success(fileInfo);
    }

    @Override
    public Result loadAllFolder(String filePid, String currentFileIds) {
        String userId = ServletUtils.getUserId();
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getFilePid, filePid);
        queryWrapper.eq(FileInfo::getUserId, userId);
        queryWrapper.eq(FileInfo::getStatus, FileStatusEnum.USING.getStatus());
        queryWrapper.eq(FileInfo::getFolderType, FileFolderTypeEnum.FOLDER.getType());
        if (StringUtils.isNoneBlank(currentFileIds)) {
            String[] ids = currentFileIds.split(",");
            queryWrapper.notIn(FileInfo::getFileId, ids);
        }
        List<FileInfo> fileInfos = this.list(queryWrapper);
        return Result.success(fileInfos);
    }

    @Override
    public Result changeFileFolder(String fileIds, String filePid) {
        if (fileIds.equals(filePid)) {
            throw new bizExceptionHandle(ResponseCodeEnum.CODE_600);
        }
        String userId = ServletUtils.getUserId();
        if (!Constants.ROOT_FILE_PID.equals(filePid)) {
            FileInfo fileInfo = this.getOne(new QueryWrapper<FileInfo>().lambda().eq(FileInfo::getFileId, filePid).eq(FileInfo::getUserId, userId), false);
            if (fileInfo == null || !FileDelFlagEnum.USING.getFlag().equals(fileInfo.getDelFlag())) {
                throw new bizExceptionHandle(ResponseCodeEnum.CODE_600);
            }
        }
        String[] ids = fileIds.split(",");
        List<FileInfo> list = this.listByIds(Arrays.asList(ids)).stream().map(fileInfo -> {
            int count = this.count(new LambdaQueryWrapper<FileInfo>().eq(FileInfo::getFilePid, filePid).eq(FileInfo::getUserId, userId).eq(FileInfo::getFileName, fileInfo.getFileName()));
            if (count > 0) {
                fileInfo.setFileName(autoRename(filePid, userId, fileInfo.getFileName()));
            }
            fileInfo.setFilePid(filePid);
            return fileInfo;
        }).collect(Collectors.toList());
        this.saveOrUpdateBatch(list);
        return Result.success(ResponseCodeEnum.CODE_200);
    }

    @Override
    public Result createDownloadUrl(String fileId) {
        FileInfo fileInfo = this.getById(fileId);
        if (fileInfo == null) {
            throw new bizExceptionHandle(ResponseCodeEnum.CODE_600);
        }
        if (FileFolderTypeEnum.FOLDER.getType().equals(fileInfo.getFolderType())) {
            throw new bizExceptionHandle(ResponseCodeEnum.CODE_600);
        }
        String code = String.valueOf(SnowflakeIdUtils.nextId());
        DownFileDto downFileDto = new DownFileDto();
        downFileDto.setCode(code);
        downFileDto.setFilePath(fileInfo.getFilePath());
        downFileDto.setFileId(fileInfo.getFileId());
        downFileDto.setFileName(fileInfo.getFileName());
        redisCache.setCacheObject(Constants.DOWN_FILE_CODE + code, downFileDto, 5, TimeUnit.MINUTES);
        return Result.success(code);
    }

    @Override
    public void download(HttpServletResponse response, String code) {
        String key = Constants.DOWN_FILE_CODE + code;
        DownFileDto downFileDto = redisCache.getCacheObject(key);
        if (downFileDto == null) {
            return;
        }
        String filePath = appConfig.getFilePath() + downFileDto.getFilePath();
        String fileName = downFileDto.getFileName();
        try {
            fileName = new String(fileName.getBytes("UTF-8"), StandardCharsets.ISO_8859_1);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setHeader("Content-Disposition", "attachment;fileName=\"" + fileName + "\"");
        response.setContentType("application/x-msdownload; charset=utf-8");
        FileUtils.readFile(response, filePath);
    }

    /**
     * 批量将文件移动到回收站
     *
     * @param fileIds 文件ID字符串，多个文件ID用逗号分隔
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result removeFile2RecycleBatch(String fileIds) {
        String[] delIds = fileIds.split(",");
        List<FileInfo> delFileInfoList = this.list(new LambdaQueryWrapper<FileInfo>()
                .eq(FileInfo::getDelFlag, FileDelFlagEnum.USING.getFlag())
                .in(FileInfo::getFileId, Arrays.asList(delIds)));

        if (delFileInfoList.isEmpty()) {
            throw new bizExceptionHandle("文件不存在");
        }

        String userId = ServletUtils.getUserId();

        List<FileInfo> filePidList = new ArrayList<>();
        // 遍历待删除的文件信息列表
        for (FileInfo fileInfo : delFileInfoList) {
            // 递归查找文件夹中的所有文件，并更新删除标志
            findFolderFiles(true, Arrays.asList(delIds), filePidList, fileInfo, userId, FileDelFlagEnum.USING.getFlag());
        }

        // 如果需要更新的文件信息列表不为空，则批量保存或更新文件信息
        if (!filePidList.isEmpty()) {
            this.saveOrUpdateBatch(filePidList);
        }
        return Result.success(ResponseCodeEnum.CODE_200);
    }

    /**
     * 递归查找文件夹中的所有文件，并更新删除标志
     *
     * @param delIds      待删除的文件ID列表
     * @param filePidList 需要更新的文件信息列表
     * @param fileInfo    当前文件信息
     * @param userId      当前用户ID
     */
    private void findFolderFiles(boolean delete, List<String> delIds, List<FileInfo> filePidList, FileInfo fileInfo, String userId, Integer delFlag) {
        //如果是删除操作
        if (delete) {
            if (delIds.contains(fileInfo.getFileId())) {
                // 如果文件ID在待删除的文件ID列表中，将删除标志设置为回收标志
                fileInfo.setDelFlag(FileDelFlagEnum.RECYCLE.getFlag());
            } else {
                // 否则，将删除标志设置为删除标志
                fileInfo.setDelFlag(FileDelFlagEnum.DEL.getFlag());
            }
        } else {
            //如果是恢复操作
            fileInfo.setDelFlag(FileDelFlagEnum.USING.getFlag());
        }
        // 将当前文件信息添加到需要更新的文件信息列表中
        filePidList.add(fileInfo);

        // 构建文件查询条件
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getFilePid, fileInfo.getFileId());
        queryWrapper.eq(FileInfo::getUserId, userId);
        queryWrapper.eq(FileInfo::getDelFlag, delFlag);

        // 查询文件夹中的所有文件
        List<FileInfo> files = this.list(queryWrapper);
        // 递归遍历文件夹中的所有文件
        files.forEach(file -> findFolderFiles(delete, delIds, filePidList, file, userId, delFlag));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result recoverFileByRecycleBatch(String fileIds) {
        String[] recoverIds = fileIds.split(",");

        List<FileInfo> list = this.list(new LambdaQueryWrapper<FileInfo>()
                .eq(FileInfo::getDelFlag, FileDelFlagEnum.RECYCLE.getFlag())
                .in(FileInfo::getFileId, Arrays.asList(recoverIds)));
        // 1.查询要恢复的文件列表
        if (list.isEmpty()) {
            throw new bizExceptionHandle("文件不存在");
        }
        // 2.恢复到根目录，文件名重复要重命名
        String userId = ServletUtils.getUserId();
        List<FileInfo> recoverFileInfoList = list.stream().map(fileInfo -> {
            int count = this.count(new LambdaQueryWrapper<FileInfo>()
                    .eq(FileInfo::getFilePid, Constants.ROOT_FILE_PID)
                    .eq(FileInfo::getUserId, userId)
                    .eq(FileInfo::getFileName, fileInfo.getFileName())
                    .eq(FileInfo::getDelFlag, FileDelFlagEnum.USING.getFlag()));
            if (count > 0) {
                fileInfo.setFileName(autoRename(fileInfo.getFilePid(), userId, fileInfo.getFileName()));
            }
            return fileInfo;
        }).collect(Collectors.toList());

        List<FileInfo> filePidList = new ArrayList<>();
        // 3.恢复文件夹下的文件
        for (FileInfo recoverFileInfo : recoverFileInfoList) {
            // 递归查找文件夹中的所有文件，并更新标志
            findFolderFiles(false, Arrays.asList(recoverIds), filePidList, recoverFileInfo, userId, FileDelFlagEnum.DEL.getFlag());
        }

        // 如果需要更新的文件信息列表不为空，则批量保存或更新文件信息
        if (!filePidList.isEmpty()) {
            this.saveOrUpdateBatch(filePidList);
        }
        return Result.success(ResponseCodeEnum.CODE_200);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result delFileBatch(String fileIds) {
        String[] delIds = fileIds.split(",");
        List<FileInfo> delFileList = this.list(new LambdaQueryWrapper<FileInfo>()
                .eq(FileInfo::getDelFlag, FileDelFlagEnum.RECYCLE.getFlag())
                .in(FileInfo::getFileId, Arrays.asList(delIds)));
        if (delFileList.isEmpty()) {
            throw new bizExceptionHandle("文件不存在");
        }

        String userId = ServletUtils.getUserId();
        List<FileInfo> filePidList = new ArrayList<>();
        for (FileInfo fileInfo : delFileList) {
            findFolderFiles(true, Arrays.asList(delIds), filePidList, fileInfo, userId, FileDelFlagEnum.DEL.getFlag());
        }
        if (!filePidList.isEmpty()) {
            this.removeByIds(filePidList.stream().map(FileInfo::getFileId).collect(Collectors.toList()));
        }
        Long useSpace = userMapper.getUseSpace(userId);
        userMapper.updateUseSpace(userId, String.valueOf(useSpace));
        String key = Constants.USER_SPACE + userId;
        UserSpaceDto userSpaceDto = redisCache.getCacheObject(key);
        userSpaceDto.setUseSpace(useSpace);
        redisCache.setCacheObject(key, userSpaceDto);
        return Result.success(ResponseCodeEnum.CODE_200);
    }

    private void checkFileName(String fileName, String filePid, Integer FolderType) {
        String userId = ServletUtils.getUserId();
        LambdaQueryWrapper<FileInfo> lqm = new LambdaQueryWrapper<>();
        lqm.eq(FileInfo::getFileName, fileName);
        lqm.eq(FileInfo::getFilePid, filePid);
        lqm.eq(FileInfo::getUserId, userId);
        lqm.eq(FileInfo::getFolderType, FolderType);
        int count = this.count(lqm);
        if (count > 0) {
            throw new bizExceptionHandle("文件名已存在");
        }
    }


    @Override
    public PageDataVo loadRecycleList(BaseEntity baseEntity) {
        String userId = ServletUtils.getUserId();
        LambdaQueryWrapper<FileInfo> wrapper = new LambdaQueryWrapper<>();
        Page<FileInfo> page = new Page<>(baseEntity.getPageNo(), baseEntity.getPageSize());
        wrapper.eq(FileInfo::getUserId, userId);
        wrapper.eq(FileInfo::getDelFlag, FileDelFlagEnum.RECYCLE.getFlag());
        wrapper.orderByDesc(FileInfo::getLastUpdateTime);
        Page<FileInfo> infoPage = this.page(page, wrapper);
        PageDataVo pageDataVo = PageUtils.getPageList(infoPage);
        return pageDataVo;
    }

    @Override
    @Transactional
    public UploadResultVo uploadFile(UploadFileDto fileDto) {
        UploadResultVo resultVo = new UploadResultVo();
        String tempFolder = null;
        try {
            if (StringUtils.isEmpty(fileDto.getFileId())) {
                fileDto.setFileId(String.valueOf(SnowflakeIdUtils.nextId()));
            }
            String fileId = fileDto.getFileId();
            String userId = ServletUtils.getUserId();
            resultVo.setFileId(fileId);
            UserSpaceDto userSpaceDto = redisCache.getCacheObject(Constants.USER_SPACE + userId);
            if (fileDto.getChunkIndex() == 0) {
                //秒传
                FileInfo fileInfo = this.getOne(new QueryWrapper<FileInfo>().lambda().eq(FileInfo::getFileMd5, fileDto.getFileMd5()).eq(FileInfo::getStatus, FileStatusEnum.USING.getStatus()), false);
                if (fileInfo != null) {
                    if (fileInfo.getFileSize() + userSpaceDto.getUseSpace() > userSpaceDto.getTotalSpace()) {
                        throw new bizExceptionHandle(ResponseCodeEnum.CODE_904);
                    }
                    fileInfo.setUserId(userId);
                    fileInfo.setFilePid(fileDto.getFilePid());
                    fileInfo.setDelFlag(FileDelFlagEnum.USING.getFlag());
                    String fileName = autoRename(fileDto.getFilePid(), userId, fileDto.getFileName());
                    fileInfo.setFileName(fileName);
                    fileInfo.setFileId(fileId);
                    this.save(fileInfo);
                    resultVo.setFileId(fileInfo.getFileId());
                    resultVo.setStatus(UploadStatusEnum.UPLOAD_SECONDS.getCode());
                    //更新使用空间
                    updateUseSpace(userSpaceDto, userId, fileInfo.getFileSize());
                    logger.info("秒传", fileDto.getFileName(), fileDto.getFileMd5());
                    return resultVo;
                }
            }

            Long fileTempSize = getFileTempSize4Redis(userId, fileId);
            if (fileDto.getFile().getSize() + userSpaceDto.getUseSpace() + fileTempSize > userSpaceDto.getTotalSpace()) {
                throw new bizExceptionHandle(ResponseCodeEnum.CODE_904);
            }

            String curUserFolderName = userId + fileId;
            tempFolder = FilenameUtils.concat(appConfig.getTempPath(), curUserFolderName);
            File tempFileFolder = new File(tempFolder);

            if (!tempFileFolder.exists()) {
                tempFileFolder.mkdirs();
            }

            File newFile = new File(tempFolder + "/" + fileDto.getChunkIndex());
            fileDto.getFile().transferTo(newFile);

            if (fileDto.getChunkIndex() < fileDto.getChunks() - 1) {
                resultVo.setStatus(UploadStatusEnum.UPLOADING.getCode());
                saveFileTempSize2Redis(userId, fileId, fileDto.getFile().getSize());
                return resultVo;
            }
            saveFileTempSize2Redis(userId, fileId, fileDto.getFile().getSize());
            //最后一个分片上传完成，保存数据库，异步合并分片
            String month = DateFormatUtils.format(new Date(), "yyyy-MM");
            String suffix = FilenameUtils.getExtension(fileDto.getFileName());

            FileTypeEnum fileTypeEnum = FileTypeEnum.getFileTypeBySuffix("." + suffix);
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileId(fileId);
            fileInfo.setUserId(userId);
            fileInfo.setFileMd5(fileDto.getFileMd5());
            fileInfo.setFilePid(fileDto.getFilePid());
            fileInfo.setFileName(autoRename(fileDto.getFilePid(), userId, fileDto.getFileName()));
            fileInfo.setDelFlag(FileDelFlagEnum.USING.getFlag());
            fileInfo.setFileCategory(fileTypeEnum.getCategory().getCategory());
            fileInfo.setFileType(fileTypeEnum.getType());
            fileInfo.setStatus(FileStatusEnum.TRANSFER.getStatus());
            fileInfo.setFolderType(FileFolderTypeEnum.FILE.getType());
            fileInfo.setFilePath(month + "/" + curUserFolderName + "." + suffix);
            this.save(fileInfo);
            //更新使用空间
            Long totalSize = getFileTempSize4Redis(userId, fileId);
            updateUseSpace(userSpaceDto, userId, totalSize);
            resultVo.setStatus(UploadStatusEnum.UPLOAD_FINISH.getCode());
            //异步合并分片
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    SpringUtils.getBean(FileInfoServiceImpl.class).transferFile(fileId, userId);
                }
            });
            return resultVo;
        } catch (bizExceptionHandle e) {
            logger.error("网盘空间不足，请扩容", e);
            throw new bizExceptionHandle(ResponseCodeEnum.CODE_904);
        } catch (Exception e) {
            logger.error("文件上传失败", e);
            FileUtils.deleteFolder(tempFolder);
            throw new bizExceptionHandle("文件上传失败");
        }
    }


    @Async
    public void transferFile(String fileId, String userId) {
        Boolean transferStatus = true;
        String targetFilePath = null;
        String cover = "";
        try {
            FileInfo fileInfo = this.getById(fileId);
            if (fileInfo == null || !FileStatusEnum.TRANSFER.getStatus().equals(fileInfo.getStatus())) {
                return;
            }
            //临时目录
            String curUserFolderName = userId + fileId;
            String tempFolder = FilenameUtils.concat(appConfig.getTempPath(), curUserFolderName);
            File tempFileFolder = new File(tempFolder);
            if (!tempFileFolder.exists()) {
                throw new bizExceptionHandle("目录不存在");
            }
            //目标目录
            File targetFolderFile = new File(appConfig.getFilePath());
            if (!targetFolderFile.exists()) {
                targetFolderFile.mkdirs();
            }
            targetFilePath = targetFolderFile.getPath() + "/" + fileInfo.getFilePath();
            //合并文件
            FileUtils.unionFile(tempFileFolder, targetFilePath, fileInfo.getFileName(), true);
            //视频文件切割
            String fileSuffix = "." + FilenameUtils.getExtension(fileInfo.getFileName());
            String month = DateFormatUtils.format(new Date(), "yyyy-MM");
            FileTypeEnum typeEnum = FileTypeEnum.getFileTypeBySuffix(fileSuffix);
            if (Objects.equals(FileTypeEnum.VIDEO.getType(), typeEnum.getType())) {
                //如果是视频就切割并且生成缩略图
                FFmpegUtils.cutFileVideo(fileId, targetFilePath);
                cover = month + "/" + curUserFolderName + Constants.PNG;
                String covePath = targetFolderFile.getAbsolutePath() + "/" + cover;
                FFmpegUtils.cutFileVideoCover(targetFilePath, 150, covePath);
            } else if (Objects.equals(FileTypeEnum.IMAGE.getType(), typeEnum.getType())) {
                //如果是图片就生成缩略图
                cover = month + "/" + fileInfo.getFilePath().replace(".", "_.");
                String covePath = targetFolderFile.getAbsolutePath() + "/" + cover;
                FFmpegUtils.createThumbnailWidthFFmpeg(new File(targetFilePath), 150, new File(covePath), true);
            }
        } catch (Exception ex) {
            logger.error("文件转码失败,文件ID:{},usedId:{}", fileId, userId);
        } finally {
            LambdaUpdateWrapper<FileInfo> updateWrapper = new UpdateWrapper<FileInfo>()
                    .lambda()
                    .set(FileInfo::getFileSize, new File(targetFilePath).length())
                    .set(FileInfo::getStatus, transferStatus ? FileStatusEnum.USING.getStatus() : FileStatusEnum.TRANSFER_FAIL.getStatus())
                    .set(FileInfo::getFileCover, cover)
                    .eq(FileInfo::getStatus, FileStatusEnum.TRANSFER.getStatus());
            super.update(updateWrapper);
        }
    }


    private void saveFileTempSize2Redis(String userId, String fileId, Long size) {
        String key = Constants.USER_SPACE_TEMP + userId + fileId;
        Long currentSize = getFileTempSize4Redis(userId, fileId);
        redisCache.setCacheObject(key, currentSize + size, 1, TimeUnit.HOURS);
    }

    private Long getFileTempSize4Redis(String userId, String fileId) {
        Object tempSize = redisCache.getCacheObject(Constants.USER_SPACE_TEMP + userId + fileId);
        if (tempSize == null) {
            return 0L;
        } else if (tempSize instanceof Integer) {
            return ((Integer) tempSize).longValue();
        } else if (tempSize instanceof Long) {
            return (Long) tempSize;
        }
        return 0L;
    }

    private void updateUseSpace(UserSpaceDto userSpaceDto, String userId, Long fileSize) {
        Integer count = fileInfoMapper.updateUseSpace(userId, fileSize, null);
        if (count == 0) {
            throw new bizExceptionHandle(ResponseCodeEnum.CODE_904);
        }
        String key = Constants.USER_SPACE + userId;
        userSpaceDto.setUseSpace(userSpaceDto.getUseSpace() + fileSize);
        redisCache.setCacheObject(key, userSpaceDto);
    }

    private String autoRename(String filePid, String userId, String fileName) {
        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getFilePid, filePid);
        queryWrapper.eq(FileInfo::getFileName, fileName);
        queryWrapper.eq(FileInfo::getUserId, userId);
        int count = this.count(queryWrapper);
        if (count > 0) {
            Integer index = fileName.lastIndexOf(".");
            if (index == -1) {
                return fileName + Constants.AUTO_RENAME;
            }
            String realName = fileName.substring(0, index);
            String suffix = fileName.substring(index);
            return realName + Constants.AUTO_RENAME + suffix;
        }
        return fileName;
    }
}




